package com.sy.simpleegg.controllermanager.helper

import android.util.Log
import com.sy.simpleegg.ext.logFile
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.cancel
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.cnbleu.serialport.SerialPort
import java.io.File
import java.io.InputStream
import java.io.OutputStream
import java.util.Queue
import java.util.concurrent.LinkedBlockingDeque

class ControlHelper(private var onDataReceivedListener: OnDataReceivedListener) {
    private var serialPort: SerialPort? = null
    private var outputStream: OutputStream? = null
    private var inputStream: InputStream? = null

    private var port: String = "/dev/"

    private var baudRate: SerialPort.BAUDRATE = SerialPort.BAUDRATE.B9600
    private var stopB: SerialPort.STOPB = SerialPort.STOPB.B1
    private var dataB: SerialPort.DATAB = SerialPort.DATAB.CS8
    private var parity: SerialPort.PARITY = SerialPort.PARITY.NONE
    private var flowcon: SerialPort.FLOWCON = SerialPort.FLOWCON.NONE

    private var speed = 10L

    private var coroutineScope = MainScope()
    private var sendJob: Job? = null
    private val cmdQueue: Queue<ByteArray> = LinkedBlockingDeque()
    private var readJob: Job? = null


//    private var onDataReceivedListener: OnDataReceivedListener? = null

    init{

    }


    fun setPort(p: String){
        this.port = p
    }

    fun setBaudRate(br: SerialPort.BAUDRATE){
        this.baudRate = br
    }

    fun setStopB(sb: SerialPort.STOPB){
        this.stopB = sb
    }

    fun setDataB(db: SerialPort.DATAB){
        this.dataB = db
    }

    fun setParity(p: SerialPort.PARITY){
        this.parity = p
    }

    fun setReadSpeed(millisecond: Long){
        speed = millisecond
    }

    fun open() {
        try {
            serialPort = SerialPort(File(port), baudRate, stopB, dataB, parity)
            outputStream = serialPort?.outputStream
            inputStream = serialPort?.inputStream
//            readThread = ReadThread()
//            readThread?.start()
            openRead()
            openSend()
        }catch (e: Exception){
            e.printStackTrace()
            logFile("打开串口失败：${e.message}")
        }
    }

    private fun openRead(){
        readJob?.cancel()

        readJob = coroutineScope.launch (Dispatchers.IO){
            try {
                while (true){
                    try {
                        val bytesBuffer = ByteArray(512)
                        val size = inputStream?.read(bytesBuffer)
                        if (size != null && size > 0){
                            val data = bytesBuffer.copyOf(size)
                            onDataReceivedListener.onDataReceived(data)
                        }
                    }catch (e: Exception){
                        e.printStackTrace()
                        Log.d(javaClass.simpleName, "read err:${e.message}")
                    }
                    delay(speed)
                }
            }catch (e: Exception){
                e.printStackTrace()
                Log.d(javaClass.simpleName, "read err2:${e.message}")
            }
        }
    }

    private fun openSend(){
        sendJob?.cancel()

        sendJob = coroutineScope.launch (Dispatchers.IO){
            try {
                while (true){
                    if (cmdQueue.size > 0){
                        var cmd:ByteArray? = null
                        while (cmdQueue.poll().also { cmd = it } != null) {
                            cmd?.let {
                                outputStream?.write(cmd)
                            }
                        }
                        delay(10)
                    }
                }
            }catch (e: Exception){
                e.printStackTrace()
            }
        }
    }

    fun close(){
        try {
            serialPort?.close()
            inputStream?.close()
            outputStream?.close()
            coroutineScope.cancel()
        }catch (e: Exception){
            e.printStackTrace()
        }
    }

    fun send(data: ByteArray){
        try {
            cmdQueue.add(data)
        }catch (e: Exception){
            e.printStackTrace()
        }
    }

    interface OnDataReceivedListener{
        fun onDataReceived(data: ByteArray)
    }

}